/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable prettier/prettier */
import { LoginEnt } from '@/models/LoginEnt';
import { LoginUser } from '@/models/LoginUser';
import { loginEntSlice } from '@/redux/toolkitSlice/LoginEntSlice';
import { loginUserSlice } from '@/redux/toolkitSlice/LoginUserSlice';
import { App, Spin } from 'antd';
import { AxiosError } from 'axios';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import React, { useEffect, useMemo } from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { YmAliOssFilePathRuleProvider, YmConfigProvider } from 'ym-design';
import { userAndEntApi } from './api';
import { request } from './api/request';
import { YmResponseCode } from './api/request/core';
import { BASEAUTHTOKENFROMSBT, BASETOKENFROMSBT, IFRAMETOKENKEY, MICROTOKENKEY, YmSafeEduAliOssConfig } from './common';
import './globalStyles/main.less';
import './public-path';
import { store } from './redux/store';
import type { MicroAppSliceType } from './redux/toolkitSlice/MicroAppSlice';
import { microAppSlice } from './redux/toolkitSlice/MicroAppSlice';
import type { IRouteItem } from './routers/routerConfig';
import { appRouter, geMicroAppRouter, getModuleORouter } from './routers/routerConfig';
import { getCurrToken } from './utils';

dayjs.locale('zh-cn');
//高德地图 PoiPicker依赖jQuery，请参见这里确定是否需要进行DomLibrary设置。
// import './utils/jquery.min.js'

function AliProvider(props: { children: React.ReactNode }) {
  const value = useMemo(() => {
    return { ...YmSafeEduAliOssConfig };
  }, []);

  return (
    <YmAliOssFilePathRuleProvider value={{ ...value, phone: store.getState().loginUser.mobile || '' }}>
      {props.children}
    </YmAliOssFilePathRuleProvider>
  );
}

// 只要主应用的loadMicroApp没有重新执行，MyInit就不会重新执行，但是把MyInit放到BasicLayout中（useRequestInterceptors）中即使loadMicroApp没有重新执行，但只要主应用切换菜单，BasicLayout组件会重新执行MyInit会重新执行
// 会导致 interceptors还未注入完成，就已经开发请求接口导致401，没有token
function MyInit(props: { browserRouter: ReturnType<typeof createBrowserRouter>; gowhere: any }) {
  const { browserRouter, gowhere } = props;
  const { message } = App.useApp();
  useEffect(() => {
    const resId = request.interceptors.response.use(
      function (response) {
        // console.log('--interceptors.response--value.3--', response)
        return response;
      },
      (err: unknown) => {
        // 登陆没成功就直接走登陆页面
        if (err instanceof AxiosError) {
          // console.log('--MyInit--request--err---:', err);
          if (!(err.config as any).noAutoShowErrorMessage) {
            message.error(err.message);
          }
          if (err.code === YmResponseCode.noRoot || err.code === YmResponseCode.noLogin) {
            message.error('登录过期，请重新登录');
            let loginHref: string;
            // 自己处理登出逻辑
            if (window.__POWERED_BY_QIANKUN__) {
              // 微应用
              loginHref = window.origin + '/sbt/login';
            } else {
              console.log(`--${gowhere ? 'iframe嵌套' : '独立'}应用--token过期--请重新登录---`);
              if (gowhere) {
                loginHref = window.origin + '/#/login';
              } else {
                loginHref =
                  window.origin +
                  (process.env.processEnvDetail.NODE_ENV === 'production' ? '/safeEduPc/login' : '/login');
              }
              // browserRouter.navigate('/login'); //有问题？？？
            }
            window.location.href = loginHref; //在当前窗口打开, window.open():新开一个窗口打开
          } else {
            // 流转到下一个拦截器
            return Promise.reject(err);
          }
        }
      },
    );

    const id = request.interceptors.request.use((config: any) => {
      // console.log('---MyInit--config--config---:', config);
      if (!config.noAuthorization) {
        config.headers['Authorization'] = getCurrToken();
      }

      return config;
    });
    // if (browserRouter && gowhere) {
    //   console.log('---MyInit--iframe--gowhere---:', gowhere)
    //   browserRouter.navigate(gowhere); // 在BasicLayout里面navigate
    // }

    return () => {
      request.interceptors.response.eject(resId);
      request.interceptors.request.eject(id);
    };
  }, []);
  return <></>;
}

interface SafeEduForEnt {
  /**
   * @desc 嵌套类型 1:应用，2：模块，3：页面
   */
  nestType: number;
  /**
   * @desc 嵌套路由地址配置
   */
  nestPath: string | string[];

  /**
   * getSafeToken接口返回的安全教育业务接口token
   */
  token: string;

  /**
   * sbt项目 authLogin 返回的token, 用于调用一些基础数据接口
   */
  baseToken: string;

  /**
   * sbt项目 authLogin 返回的authToken, 用于调用一些基础数据接口
   */
  baseAuthToken: string;

  /**
   * 登录用户id
   */
  personId: string;
  /**
   * 用户角色 0：超管，1：普通管理员，2：普通员工
   */
  loginRole?: number;
  /**
   * 企业id
   */
  entId: string;
  /**
   * 1:协会， 0：企业
   */
  organizationType: number;
}

type TSafeEduStateToParent = {
  name: 'micro-safe-edu';
  type: string; //'childHasLoaded';
  data?: any;
};

type OnGlobalStateChangeCallback = (state: SafeEduForEnt, prevState: SafeEduForEnt) => void;
type SafeEduProps = {
  onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void;
  setGlobalState: (state: TSafeEduStateToParent) => boolean;
  offGlobalStateChange: () => boolean;
  container: HTMLDivElement;
  name: string;
};

let root: ReactDOM.Root;
function render(props: Partial<SafeEduProps>) {
  const { container } = props;
  let finalRouter: IRouteItem[] = appRouter;
  let gowhere: any;
  let browserRouter: ReturnType<typeof createBrowserRouter>;

  const rootDom = container ? container.querySelector('#root') : document.getElementById('root');
  if (rootDom) {
    root = ReactDOM.createRoot(rootDom);
    // BUG: 已经加载 /plannedManage/examPlan页面的情况下， 刷新浏览器,然后关闭页面，再次进入页面 props.name 变成了 'micro-safe-edu_1'
    // console.log('---props.name1-----:', props.name);
    if (props.onGlobalStateChange && props.name?.includes('micro-safe-edu')) {
      props.onGlobalStateChange((curState, prevState) => {
        // console.log(curState, prevState, '-----检查前后参数的改变');
        // state: 变更后的状态; prev 变更前的状态
        console.log('主应用发送过来的消息-micro-safe-edu--curState--prevState--：', curState, prevState);
        const { nestType, nestPath, entId, personId, token, baseToken, loginRole, baseAuthToken } = curState;
        localStorage.setItem(MICROTOKENKEY, token);
        localStorage.setItem(BASETOKENFROMSBT, baseToken);
        localStorage.setItem(BASEAUTHTOKENFROMSBT, baseAuthToken);

        store.dispatch(
          loginEntSlice.actions.updateLoginEnt(new LoginEnt({ entId, organizationType: curState.organizationType })),
        );
        store.dispatch(loginUserSlice.actions.updateLoginUser(new LoginUser({ personId, loginRole })));
        store.dispatch(
          microAppSlice.actions.updateMicroAppStore({
            ...curState,
            onGlobalStateChange: props.onGlobalStateChange,
            setGlobalState: props.setGlobalState,
          }),
        );
        if (nestType) {
          if (nestType === 1 || nestType === 3) {
            //应用，页面
            finalRouter = geMicroAppRouter(nestType);
          } else if (nestType === 2) {
            //模块
            finalRouter = getModuleORouter(nestType, nestPath);
          }
        }
      }, true);
      props.setGlobalState?.({ name: 'micro-safe-edu', type: 'childHasLoaded' }); //告诉父级应用自己加载好了
    } else if (window.location.search && !window.__POWERED_BY_QIANKUN__) {
      const usp = new URLSearchParams(window.location.search);
      gowhere = usp.get('gowhere');
      const token = usp.get('token');
      if (gowhere && token) {
        console.log(
          '--iframe嵌入安全教育  token--gowhere--window.location.search--',
          token,
          gowhere,
          window.location.search,
        );
        //通过iframe嵌套
        window.__POWERED_BY_IFRAME__ = true;
        // 获取entdId
        userAndEntApi
          .getEntdIdBySafeEducToken({ token })
          .then((res) => {
            // console.log('--res--:', res);
            const currEntId = res.msg;
            localStorage.setItem(IFRAMETOKENKEY, token); //同一域名下，几个应用用同一个名字的token,那么这个token不是隔离的，任何一个应用改变了该token,其余应用的该token也会改变
            store.dispatch(
              loginEntSlice.actions.updateLoginEnt(new LoginEnt({ entId: currEntId, organizationType: 1 })),
            );
            store.dispatch(loginUserSlice.actions.updateLoginUser(new LoginUser({ personId: '', loginRole: 1 })));
          })
          .catch((err) => {
            console.log('--index.tsx--getEntdIdBySafeEducToken--err--:', err);
          })
          .finally(() => {
            store.dispatch(microAppSlice.actions.updateMicroAppStore({ nestPath: gowhere as string, nestType: 4 }));
            finalRouter = geMicroAppRouter(4);
          });
      }
    }

    browserRouter = createBrowserRouter(finalRouter, {
      basename: window.__POWERED_BY_QIANKUN__
        ? '/sbt/home/Y19'
        : process.env.processEnvDetail.REACT_APP_browserRouterBaseName,
    });

    root.render(
      <YmConfigProvider theme={{ token: { wireframe: false } }}>
        <App>
          <AliProvider>
            <MyInit browserRouter={browserRouter} gowhere={gowhere} />
            <Provider store={store}>
              <RouterProvider router={browserRouter} fallbackElement={<Spin />} />
            </Provider>
          </AliProvider>
        </App>
      </YmConfigProvider>,
    );
  }
}

/**
 * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log('micro-safe-edu bootstraped');
}

/**
 * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法
 */
export async function mount(props: SafeEduProps) {
  render(props);
}

/**
 * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例
 */
export async function unmount(props: MicroAppSliceType) {
  console.log('micro-safe-edu-unmount-props', props);
  store.dispatch(microAppSlice.actions.updateMicroAppStore({}));
  root && root.unmount();
  window.__POWERED_BY_QIANKUN__ = false;
}

if (!window.__POWERED_BY_QIANKUN__) {
  render({});
}

// 热更新
// @ts-ignore
if (module.hot) {
  // @ts-ignore
  module.hot.accept((err) => {
    if (err) {
      console.error('module.hot, ', err);
    }
  });
}
